home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 001-025 / scopedisk3 / 68kasm / src / symtab.c < prev    next >
C/C++ Source or Header  |  1995-03-18  |  30KB  |  996 lines

  1. /*------------------------------------------------------------------*/
  2. /*                                    */
  3. /*              MC68000 Cross Assembler                */
  4. /*                                    */
  5. /*          Copyright    (c) 1985 by Brian R. Anderson            */
  6. /*                                    */
  7. /*        Symbol table manipulation -    March 18, 1988            */
  8. /*                                    */
  9. /*   This program may be copied    for personal, non-commercial use    */
  10. /*   only, provided that the above copyright notice is included        */
  11. /*   on    all copies of the source code.    Copying    for any    other use   */
  12. /*   without the consent of the    author is prohibited.            */
  13. /*                                    */
  14. /*------------------------------------------------------------------*/
  15. /*                                    */
  16. /*        Originally published (in Modula-2) in            */
  17. /*        Dr.    Dobb's Journal, April, May, and June 1986.          */
  18. /*                                    */
  19. /*    AmigaDOS conversion copyright (c) 1988 by Charlie Gibbs.    */
  20. /*                                    */
  21. /*------------------------------------------------------------------*/
  22.  
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include "a68kdef.h"
  26. #include "a68kglb.h"
  27.  
  28. long Value;    /* Passed from ReadSymTab to CalcValue */
  29.  
  30. /* Functions */
  31. extern int  Instructions(), ObjDir();
  32. extern int  GetInstModeSize(), GetMultReg();
  33. extern int  GetArgs(), GetAReg();
  34. extern long AddrBndW(),    AddrBndL();
  35. extern char *malloc();
  36. extern FILE *fopen();
  37.  
  38. int  LineParts(), GetField(), ReadSymTab(), GetSize(), OpenIncl();
  39. long GetValue(), CalcValue();
  40.  
  41.  
  42.  
  43. int OpenIncl (name, dirlist) char name[], dirlist[];
  44. /* Opens the file whose    name is    in "name".  The current
  45.     directory is tried first.  If that fails, the directory
  46.     names in "dirlist" (separated by commas) are then tried
  47.     until either a file    is found or the    list is    exhausted.
  48.     If the file    is found in a subdirectory, "name" is
  49.     modified to    include    the entire path    specification.
  50.     If another input file is open when this routine is called,
  51.     it is closed first.     Returns TRUE if successful, FALSE if not.  */
  52. {
  53.     register int i;
  54.     char dirname[MAXLINE];
  55.  
  56.     if (InFile != NULL)
  57.     fclose (InFile);    /* Close the inner file    */
  58.  
  59.     if ((InFile    = fopen    (name, "r")) != NULL)
  60.     return (TRUE);        /* Found it in current directory */
  61.  
  62.     i =    0;
  63.     while (dirlist[i] != '\0') {
  64.     i = GetField (dirlist, i, dirname);
  65.     if ((dirname[i-1] != '/') && (dirname[i-1] != ':'))
  66.         strcat (dirname, "/");      /* Slash after directory name */
  67.     strcat (dirname, name);
  68.     if ((InFile = fopen (dirname, "r")) != NULL) {
  69.         strcpy (name, dirname);    /* Return entire path */
  70.         return (TRUE);    /* Found it in a subdirectory */
  71.     }
  72.     if (dirlist[i] != '\0')
  73.         i++;        /* Skip    over separator and try again */
  74.     }
  75.     return (FALSE);        /* Couldn't find it anywhere */
  76. }
  77.  
  78.  
  79.  
  80. int LineParts (dummy) int dummy;
  81. /* Gets    the next statement and extracts    its component parts.
  82.     If end of file is reached, and we're in a macro or include
  83.     file, the file is closed and the next outermost file is
  84.     continued.    If we have reached the end of the source file,
  85.     or encounter an ENDM or MEXIT directive, the current input
  86.     file is closed and TRUE is returned.
  87.  
  88.     If we're in a user macro (indicated by UPtr being nonzero),
  89.     we'll get the next statement from the save area in memory instead.
  90.  
  91.     Macro arguments, if    any, are substituted.
  92.  
  93.     LineCount is incremented if    a statement was    successfully read.
  94.  
  95.     If this is the first call of this routine (i.e. LineCount is zero)
  96.     and    HeaderFN is not    a null string, we'll return an INCLUDE statement
  97.     requesting the specified header file, rather than reading the first
  98.     statement from the source file.
  99.  
  100.     The    following fields are set up:
  101.     Line    - statement line image
  102.     Label    - instruction label (without trailing colon)
  103.     OpCode    - instruction mnemonic (converted to upper case)
  104.     SrcOp    - first    (source) operand
  105.     DestOp    - second (destination) operand
  106.     Size    - size from OpCode
  107.     LabLoc    - displacement to start    of instruction label
  108.     OpLoc    - displacement to start    of instruction mnemonic
  109.     SrcLoc    - displacement to start    of source operand
  110.     DestLoc    - displacement to start    of destination operand
  111.     InFNum    - decremented if end of    file is    reached
  112.     InF    - incremented if end of    file is    reached
  113.     LabLine    - set to LineCount if this line    is labeled
  114.             (unless    it's a local label)
  115.                                 */
  116. {
  117.     register int i, j, c;
  118.     register char *argptr;
  119.     char subline[MAXLINE];
  120.  
  121.     while (1) {    /* Repeat until    we get something (not end of INCLUDE) */
  122.     Line[0]    = Label[0] = OpCode[0] = SrcOp[0] = DestOp[0] =    '\0';
  123.     LabLoc = OpLoc = SrcLoc    = DestLoc = 0;
  124.  
  125.     if ((LineCount==0) && (HeaderFN[0])) {    /* Header file */
  126.         strcpy (Line, "        INCLUDE ");  /* Make an INCLUDE stmt. */
  127.         strcat (Line, HeaderFN);
  128.         strcat (Line, "        ;Generated for header file");
  129.         strcpy (OpCode, "INCLUDE"); /* Dummy op code */
  130.         OpLoc = 8;
  131.         strcpy (SrcOp, HeaderFN);    /* Dummy source    operand    */
  132.         SrcLoc = 16;
  133.         LineCount++;
  134.         errlim = AddrAdv = InstSize    = nO = nS = nD = nX = 0;
  135.         PrntAddr = FALSE;
  136.         return (FALSE);
  137.     }
  138.  
  139.     if (InF->UPtr != 0) {            /* User    macro input */
  140.         strcpy (Line, InF->UPtr);
  141.         InF->UPtr += strlen    (Line) + 1;
  142.         c =    '\n';
  143.     } else {                /* Normal file input */
  144.         i =    0;
  145.         while ((c=getc(InFile)) != '\n') {  /* Get Line, expanding tabs */
  146.         if (c == 26)
  147.             c =    EOF;            /* Catch MS-DOS    EOF char. */
  148.         if (c == EOF) {
  149.             if (i > 0) {        /* Last    line has no \n -   */
  150.             c = ungetc (c, InFile);    /*  push back the EOF and  */
  151.             c = '\n';               /*  process the last line. */
  152.             }
  153.             break;
  154.         }
  155.         if ((i < (MAXLINE - 1))    && (c != 13)) {    /* Ignore excess */
  156.             if ((c != '\t') || KeepTabs)
  157.             Line[i++] = c;        /* Normal character */
  158.             else {
  159.             j = (i + 8) & ~7;    /* Expand tabs */
  160.             if (j >    (MAXLINE - 1))
  161.                 j =    MAXLINE    - 1;    /* Tabbed off the end */
  162.             while (i < j)
  163.                 Line[i++] =    ' ';
  164.             }
  165.         }
  166.         }
  167.         Line[i] = '\0';
  168.     }
  169.     if ((Line[0] !=    '\0') && (Line[0] != '*') && (Line[0] != ';')) {
  170.  
  171.         /* --------    Macro argument substitution routine -------- */
  172.  
  173.         i =    0;
  174.         while ((Line[i] != '\0') && (InF->NArg != -1)) {
  175.         if ((subline[i]    = Line[i]) != '\\') {
  176.             i++;
  177.             continue;
  178.         }
  179.         if (Line[i+1] == '@') { /* \@ - substitute macro number */
  180.             subline[i] = '.';
  181.             j =    InF->MCnt % 1000;
  182.             subline[i+1] = j / 100 + '0';
  183.             j =    j % 100;
  184.             subline[i+2] = j / 10 + '0';
  185.             subline[i+3] = j % 10 + '0';
  186.             subline[i+4] = '\0';
  187.             strcat (subline, &Line[i+2]); /* Remainder of Line */
  188.             strcpy (Line, subline);    /* Replace Line    */
  189.             i =    0;            /* Check for more */
  190.             continue;
  191.         }
  192.         if ((Line[i+1] < '0') || (Line[i+1] > '9')) {
  193.             i++;        /* False alarm - it's a  */
  194.             continue;        /*  named local    variable */
  195.         }
  196.  
  197.         subline[i++] = '\0';    /* Chop off first portion */
  198.         j = 0;            /* Get argument    index */
  199.         while ((Line[i]    >= '0') && (Line[i] <= '9')) {
  200.             j *= 10;
  201.             j += Line[i++] - '0';       /* Current digit */
  202.         }
  203.         if ((j > 0) && (j <= InF->NArg)) {
  204.             argptr = InF->NPtr;
  205.             while (j > 0) {        /* Find    argument */
  206.             argptr += strlen (argptr) + 1;
  207.             j--;
  208.             }
  209.             strcat (subline, argptr);    /* Insert it */
  210.         }
  211.         strcat (subline, &Line[i]);    /* Remainder of    Line */
  212.         strcpy (Line, subline);        /* Replace Line    */
  213.         i = 0;                /* Check for more */
  214.         }
  215.  
  216.         /* ------- Break up    Line into its component    parts ------- */
  217.  
  218.         i =    0;
  219.         if (!isspace(Line[i])) {
  220.         i = GetField (Line, i, Label);        /* Label */
  221.         j = strlen(Label) - 1;
  222.         while ((j >= 0)    && (Label[j] ==    ':'))
  223.             Label[j--] = '\0';  /* Strip trailing colon(s) */
  224.         }
  225.         while (isspace(Line[i]))
  226.         i++;            /* Skip    over to    mnemonic */
  227.         if ((Line[i] != ';') && (Line[i] != '\0')) {
  228.         while (OpLoc ==    0) {
  229.             OpLoc = i;
  230.             i =    GetField (Line,    i, OpCode);    /* Mnemonic */
  231.             j =    strlen(OpCode) - 1;
  232.             if ((j >= 0) && (OpCode[j] == ':')) {
  233.             if (Label[0])
  234.                 Error (OpLoc, MultLab);    /* Multiple labels */
  235.             else {
  236.                 strcpy (Label, OpCode);    /* It's a label */
  237.                 while ((j >= 0) && (Label[j] == ':'))
  238.                 Label[j--] = '\0';
  239.             }
  240.             OpLoc =    0;
  241.             OpCode[0] = '\0';
  242.             while (isspace(Line[i]))
  243.                 i++;
  244.             }
  245.         }
  246.         while (isspace(Line[i]))
  247.             i++;        /* Skip    over to    operands */
  248.         if ((Line[i] !=    ';') && (Line[i] != '\0')) {
  249.             SrcLoc = i;
  250.             i =    GetField (Line,    i, SrcOp);    /* Op1 (source)    */
  251.             if (Line[i]    == ',')
  252.             i++;
  253.             if (!isspace(Line[i])&&(Line[i]!='\0')&&(Line[i]!=';')) {
  254.             DestLoc    = i;
  255.             i = GetField (Line, i, DestOp);    /* Op2 (dest.) */
  256.             }
  257.         }
  258.         }
  259.     }
  260.     if ((j = strlen    (OpCode)) == 0)
  261.         Size = S0;
  262.     else {
  263.         Size = GetSize (OpCode);    /* Instruction operand size */
  264.         for    (i = 0;    i < j; i++)        /* Convert OpCode */
  265.         OpCode[i] = toupper(OpCode[i]);    /*  to upper case */
  266.     }
  267.  
  268.     /* ------ If we    have reached the end of    a macro    or ------ */
  269.     /* ------ include file,    return to the calling file ------ */
  270.  
  271.     i = (c == EOF);                    /* End of file */
  272.     if ((Dir != Macro) && (SkipNest    == 0)) {    /* Macro exits */
  273.         i |= (strcmp (OpCode, "ENDM") == 0);
  274.         i |= (strcmp (OpCode, "MEXIT") == 0);
  275.     }
  276.  
  277.     if (!i)    {            /* Not end of file or macro */
  278.         if ((PrevDir == MacCall) &&    (strcmp    (OpCode, "MACRO") == 0))
  279.         continue;        /* Ignore macro    header */
  280.         if (SkipNest == 0)        /* We're not skipping */
  281.         break;            /* We got something */
  282.         else {
  283.         (InF->Line)++;        /* Count skipped lines */
  284.         if (strcmp (OpCode, "ENDC") == 0) SkipNest--;
  285.         else if    (strcmp    (OpCode, "ENDIF") == 0) SkipNest--;
  286.         else if    (strcmp    (OpCode, "IFEQ") == 0) SkipNest++;
  287.         else if    (strcmp    (OpCode, "IFNE") == 0) SkipNest++;
  288.         else if    (strcmp    (OpCode, "IFGT") == 0) SkipNest++;
  289.         else if    (strcmp    (OpCode, "IFGE") == 0) SkipNest++;
  290.         else if    (strcmp    (OpCode, "IFLT") == 0) SkipNest++;
  291.         else if    (strcmp    (OpCode, "IFLE") == 0) SkipNest++;
  292.         else if    (strcmp    (OpCode, "IFC" ) == 0) SkipNest++;
  293.         else if    (strcmp    (OpCode, "IFNC") == 0) SkipNest++;
  294.         else if    (strcmp    (OpCode, "IFD" ) == 0) SkipNest++;
  295.         else if    (strcmp    (OpCode, "IFND") == 0) SkipNest++;
  296.         continue;
  297.         }
  298.     }
  299.     if (InFNum == 0)
  300.         break;            /* End of source file */
  301.     if (InF->UPtr == 0) {
  302.         fclose (InFile);        /* Close inner file */
  303.         InFile = NULL;
  304.     }
  305.     NextFNS    = InF->NPtr;        /* Release space on name stack */
  306.     InFNum--;            /* Return to outer file    */
  307.     InF++;
  308.     if (InFNum < OuterMac)
  309.         OuterMac = 0;        /* End of outer    macro */
  310.     if ((InF->UPtr == 0) &&    (InFile    == NULL)) {
  311.         InFile = fopen (InF->NPtr, "r");
  312.         fseek (InFile, InF->Pos, 0);
  313.     }
  314.     }
  315.     LineCount++;            /* Bump    line counter */
  316.     (InF->Line)++;
  317.     if ((Label[0] != '\0') && (Label[0] != '\\'))
  318.     if ((Label[0] <    '0') || (Label[0] > '9'))
  319.         LabLine = LineCount;    /* Save    line number of label */
  320.     if (Quiet != 0) {
  321.     if ((LineCount % Quiet)    == 0) {    /* Display progress */
  322.         fprintf (stderr, "%4d\b\b\b\b", LineCount);
  323. #ifdef AZTEC_C
  324.         fflush (stderr);        /* Make    sure it    gets out */
  325. #endif
  326. #ifdef PDC
  327.         fflush (stderr);        /* Make    sure it    gets out */
  328. #endif
  329.     }
  330.     }
  331.     errlim = AddrAdv = InstSize    = nO = nS = nD = nX = 0;
  332.     PrntAddr = FALSE;
  333.  
  334.     if ((LineCount >= DebugStart) && (LineCount    <= DebugEnd))
  335.     printf ("%6lx %4d %s\n", AddrCnt, LineCount, Line);
  336.  
  337.     return (c == EOF);
  338. }
  339.  
  340.  
  341.  
  342. int GetField (source, pos, dest) char source[],    dest[];    int pos;
  343. /* Gets    a field    from "source", starting at position "pos".
  344.     Result is returned in "dest".
  345.     Stops on the first comma, semicolon, or white space    not
  346.     enclosed within    apostrophes or parentheses.
  347.     Returns stopping location.
  348.     If already at end of "source", "dest" is set to null string. */
  349. {
  350.     register char *s, *d;
  351.     register int parncnt, instring;
  352.  
  353.     s =    source + pos;    /* Use pointers    for speed */
  354.     d =    dest;
  355.     instring = FALSE;
  356.     parncnt = 0;
  357.  
  358.     while (*s) {
  359.     if (instring) {
  360.         *d++ = *s;
  361.     } else {
  362.         if (isspace(*s) || (*s == ';'))
  363.         break;
  364.         else if ((*s == ',') && (parncnt == 0))
  365.         break;
  366.         else {
  367.         *d++ = *s;
  368.         if (*s == '(')
  369.             parncnt++;
  370.         else if    (*s == ')')
  371.             parncnt--;
  372.         }
  373.     }
  374.     if (*s == '\'')
  375.         instring = !instring;
  376.     s++;
  377.     }
  378.     *d = '\0';
  379.     return (s -    source);
  380. }
  381.  
  382.  
  383.  
  384. AddMacLine (line) char *line;
  385. /* Adds    the line in "line" to the heap. */
  386. {
  387.     HeapSpace (strlen (line) + 1);    /* Make    sure we    have room */
  388.     strcpy (HeapLim, line);        /* Store the line */
  389.     HeapLim += strlen (line) + 1;    /* Update heap limit */
  390. }
  391.  
  392.  
  393.  
  394. long GetValue (operand,    loc) char operand[]; int loc;
  395. /* Determines value of expression */
  396. /* Hunk2 is set    to hunk    number of result (ABSHUNK if absolute).
  397.    If the expression consists solely of    self-defining terms,
  398.     DefLine2 is set    to zero.  Otherwise, DefLine2 is set
  399.     to the highest statement number    in which any symbol in
  400.     the expression was defined.  If    the expression contains
  401.     any undefined symbols, DefLine2    is set to NODEF.
  402.     The    following code is based    on a regular-to-Polish expression
  403.     converter described in "A Guide to FORTRAN IV Programming"
  404.     by Daniel D. McCracken (John Wiley & Sons, Inc.    1965,
  405.     3rd printing August 1968).  However, rather than generating
  406.     the entire Polish expression, this routine will    evaluate
  407.     and combine two    terms as soon as an operator of    lower
  408.     precedence is encountered.                */
  409. {
  410.     register char *o, *s;
  411.     char tempop[MAXLINE];
  412.     int     oloc, parncnt,    nextprec, instring;
  413.     long templong;
  414.     struct TermStack *origterm;
  415.  
  416.     Hunk2 = ABSHUNK;
  417.     parncnt = DefLine2 = 0;
  418.     o =    NextFNS;
  419.     if ((templong = (o - Heap) & 3L) !=    0)
  420.     o += 4 - templong;
  421.     origterm = Term = (struct TermStack    *) o;    /* Term    stack */
  422.     Ops    = (struct OpStack *) InF;        /* Operator stack */
  423.     Ops--;
  424.     ParseSpace (0);
  425.     Ops->chr = ' ';     /* Prime the operator stack */
  426.     Ops->prec =    -1;
  427.     if ((char *) Ops < Low2)
  428.     Low2 = (char *)    Ops;
  429.  
  430.     /* Get all tokens.
  431.     Terms are evaluated, and operator precedence is    determined.
  432.     Left and right parentheses are given a precedence of
  433.         1 and 2 respectively.
  434.     Binary operators are given precedence values starting at 3.
  435.     Unary plus is ignored.
  436.     Unary minus is converted to zero minus the remainder of
  437.         of the expression -    its precedence is set to 9 to
  438.         ensure that    the simulated unary operator is    evaluated
  439.         before the remainder of the    expression.
  440.     Logical    not (~), being another unary operator, is converted
  441.         to -1 exclusive-ORed with the remainder of the expression.
  442.         Its    precedence is also set to 9.                */
  443.  
  444.     o =    operand;            /* Current position in operand */
  445.  
  446.     while (1) {
  447.     while (*o == '(') {             /* Left parenthesis */
  448.         Ops--;
  449.         ParseSpace (0);
  450.         Ops->chr  =    '(';
  451.         Ops->prec =    1;
  452.         if ((char *) Ops < Low2)
  453.         Low2 = (char *)    Ops;
  454.         parncnt++;
  455.         o++;
  456.     }
  457.     if ((*o    == '+') || (*o == '-') || (*o == '~')) {    /* Unary op */
  458.         if (*o != '+') {    /* Ignore unary plus */
  459.         Ops--;
  460.         ParseSpace (sizeof (struct TermStack));
  461.         Term->value   =    (*o == '-') ? 0 : -1;   /* Dummy value */
  462.         Term->hunk    =    ABSHUNK;
  463.         Term->oploc   =    loc + (o - operand);
  464.         Term->defline =    0;
  465.         Term++;
  466.         if ((char *) Term > High2)
  467.             High2 = (char *) Term;
  468.         Ops->chr  = *o;        /* Now get the operator    itself */
  469.         Ops->prec = 9;        /* Do it ASAP */
  470.         if ((char *) Ops < Low2)
  471.             Low2 = (char *) Ops;
  472.         }
  473.         o++;
  474.         if (*o == '(')
  475.         continue;    /* Inner parenthesized expression */
  476.     }
  477.     oloc = loc + (o    - operand);
  478.  
  479.     s = tempop;                /* Get a term */
  480.     if (*o == '*') {        /* It's a location counter reference, */
  481.         *s++ = *o++;    /*   not a multiplication operator!   */
  482.     } else {
  483.         if (IsOperator (o) || (*o == '\0')) {
  484.         Error (oloc, OperErr);    /* Unexpected operator or no terms */
  485.         return (0L);
  486.         }
  487.         instring = FALSE;
  488.         while (*o) {
  489.         if (*o == '\'')
  490.             instring = !instring;   /* String delimiter    */
  491.         if (!instring && (IsOperator (o) || (*o    == '~')))
  492.             break;            /* Found an    operator - stop    */
  493.         *s++ = *o++;            /* Get a character */
  494.         }
  495.     }
  496.     *s = '\0';
  497.     ParseSpace (sizeof (struct TermStack));
  498.     Term->value   =    CalcValue (tempop, oloc);
  499.     Term->hunk    =    Hunk2;
  500.     Term->oploc   =    oloc;
  501.     Term->defline =    DefLine2;
  502.     Term++;
  503.     if ((char *) Term > High2)
  504.         High2 = (char *) Term;
  505.     Hunk2 =    DefLine2 = 0;
  506.  
  507.     while (*o == ')') {                     /* Right parenthesis */
  508.         if (parncnt    == 0) {
  509.         Error ((int) (loc + (o - operand)), OperErr);
  510.         return (0L);
  511.         }
  512.         CondCalc (2);        /* Unstack what    we can */
  513.         if (Ops->chr == '(')
  514.         Ops++;            /* Drop    paired parentheses */
  515.         else {
  516.         Ops--;
  517.         ParseSpace (0);
  518.         Ops->chr  = ')';        /* Stack parenthesis for now */
  519.         Ops->prec = 2;
  520.         if ((char *) Ops < Low2)
  521.             Low2 = (char *) Ops;
  522.         }
  523.         parncnt--;
  524.         o++;
  525.     }
  526.     if (*o)    {
  527.         if (!IsOperator (o)    || (*o == '(')) {
  528.         Error ((int) (loc + (o - operand)), OperErr);
  529.         return (0L);        /* Expected an operator    */
  530.         }
  531.         switch (*o)    {
  532.         case '+': nextprec = 3; break;
  533.         case '-': nextprec = 3; break;
  534.         case '*': nextprec = 4; break;
  535.         case '/': nextprec = 4; break;
  536.         case '&': nextprec = 5; break;
  537.         case '!': nextprec = 5; break;
  538.         case '|': nextprec = 5; break;
  539.         case '<': nextprec = 6; break;
  540.         case '>': nextprec = 6; break;
  541.         }
  542.         CondCalc (nextprec);    /* Unstack what    we can */
  543.         Ops--;
  544.         ParseSpace (0);
  545.         Ops->chr  =    *o;        /* Stack the next operator */
  546.         Ops->prec =    nextprec;
  547.         if ((char *) Ops < Low2)
  548.         Low2 = (char *)    Ops;
  549.         if ((*o == '<') || (*o == '>'))
  550.         o++;    /* Skip    over two-character operator */
  551.         o++;
  552.     } else {
  553.         if (parncnt) {
  554.         Error ((int) (loc + (o - operand)), OperErr);
  555.         return (0L);    /* Too many left parentheses */
  556.         }
  557.         CondCalc (0);        /* Unstack what's left */
  558.         if (--Term != origterm)    /* Should be only one term left    */
  559.         Error (Term->oploc, OperErr);        /* Parser bug? */
  560.         Hunk2    = Term->hunk;
  561.         DefLine2 = Term->defline;
  562.         return (Term->value);    /* Final value */
  563.     }
  564.     }
  565. }
  566.  
  567.  
  568.  
  569. CondCalc (newprec) int newprec;
  570. /* As long as the top operator on the operator stack has a precedence
  571.     greater than or equal to the contents of "newprec", this routine
  572.     will pop the two top terms from the    term stack, combine them
  573.     according to the operator on the top of the    operator stack (which
  574.     is also popped), and push the result back onto the term stack. */
  575. {
  576.     while (Ops->prec >=    newprec) {    /* Unstack an operator */
  577.     Term -=    2;
  578.     if (Ops->chr ==    '+') {          /* Relocatable addition */
  579.         if (Term->hunk == ABSHUNK)
  580.         Term->hunk = (Term+1)->hunk;    /* A+R */
  581.         else if ((Term+1)->hunk != ABSHUNK)    {
  582.         Error ((Term+1)->oploc,    RelErr);    /* R+R - error */
  583.         Term->hunk = ABSHUNK;        /* Make    it absolute */
  584.         }
  585.     } else if (Ops->chr == '-') {           /* Subtraction */
  586.         if (Term->hunk == (Term+1)->hunk)
  587.         Term->hunk = ABSHUNK;        /* R-R - absolute */
  588.         else if (Term->hunk    != ABSHUNK) {        /* R-R across hunks    */
  589.         Error ((Term+1)->oploc,    RelErr);    /*    is an error -    */
  590.         Term->hunk = ABSHUNK;            /* make it absolute    */
  591.         }
  592.     } else if ((Term->hunk != ABSHUNK)
  593.     || ((Term+1)->hunk != ABSHUNK))    {
  594.         Error (Term->oploc,RelErr);        /* All other operations    */
  595.         Term->hunk = ABSHUNK;        /*   must be absolute    */
  596.     }
  597.     if ((Term+1)->defline >    Term->defline)    /* Definition */
  598.         Term->defline = (Term+1)->defline;    /*  line nos. */
  599.  
  600.     switch (Ops->chr) {        /* Perform the operation */
  601.     case '+':
  602.         Term->value    += (Term+1)->value;
  603.         break;
  604.     case '-':
  605.         Term->value    -= (Term+1)->value;
  606.         break;
  607.     case '*':
  608.         Term->value    *= (Term+1)->value;
  609.         break;
  610.     case '/':
  611.         if ((Term+1)->value)
  612.         Term->value /= (Term+1)->value;
  613.         else
  614.         Term->value = 0;     /*    Don't divide by zero */
  615.         break;
  616.     case '&':
  617.         Term->value    &= (Term+1)->value;
  618.         break;
  619.     case '!':
  620.     case '|':
  621.         Term->value    |= (Term+1)->value;
  622.         break;
  623.     case '<':
  624.         Term->value    <<= (Term+1)->value;
  625.         break;
  626.     case '>':
  627.         Term->value    >>= (Term+1)->value;
  628.         break;
  629.     case '~':
  630.         Term->value    ^= (Term+1)->value;
  631.         break;
  632.     default:
  633.         Error (Term->oploc,    OperErr);    /* Parser bug? */
  634.         break;
  635.     }
  636.     Term++;
  637.     Ops++;
  638.     }
  639. }
  640.  
  641.  
  642.  
  643. int IsOperator (o) char    *o;
  644. /* Tests whether "o" points to a valid operator or parenthesis. */
  645. {
  646.     return ((*o    == '+')
  647.     ||  (*o    == '-')
  648.     ||  (*o    == '*')
  649.     ||  (*o    == '/')
  650.     ||  (*o    == '&')
  651.     ||  (*o    == '!') || (*o == '|')
  652.     || ((*o    == '<') && (*(o+1) == '<'))
  653.     || ((*o    == '>') && (*(o+1) == '>'))
  654.     ||  (*o    == '(')
  655.     ||  (*o    == ')'));
  656. }
  657.  
  658.  
  659.  
  660. long CalcValue (operand, loc) char operand[]; int loc;
  661. /* Evaluates a single term (called by GetValue).
  662.     Hunk2 receives relative hunk number    (ABSHUNK if absolute).
  663.     If the value is a symbol, DefLine2 is set to the line number
  664.     where it was defined, or NODEF if it is    undefined.
  665.     For self-defining terms, DefLine2 is set to zero.    */
  666. {
  667.     register long result;    /* Result is calculated    here */
  668.     register int  i, radix;
  669.     int     neg, numstart,    local;
  670.     char maxdig;    /* Highest valid digit in current radix    */
  671.     char delim;        /* String delimiter (' or ") */
  672.  
  673.     local = FALSE;
  674.     if (neg = (operand[0] == '-'))
  675.     numstart = 1;            /* Negative value */
  676.     else {
  677.     numstart = 0;            /* Positive value */
  678.     i = strlen(operand) - 1;
  679.     if (operand[i] == '$') {
  680.         local = TRUE;        /* Assume it's a local label */
  681.         while (i > 0) {
  682.         i--;
  683.         if ((operand[i]    < '0') || (operand[i] > '9')) {
  684.             local = FALSE;    /* False alarm */
  685.             break;
  686.         }
  687.         }
  688.     }
  689.     }
  690.     Hunk2 = ABSHUNK;            /* Assume value    is absolute */
  691.     DefLine2 = 0;            /* and self-defining */
  692.  
  693.     if ((operand[numstart] >= '0') && (operand[numstart] <= '9')) {
  694.     radix =    10;        /* Decimal number */
  695.     maxdig = '9';
  696.     } else if (operand[numstart] == '$') {
  697.     radix =    16;        /* Hexadecimal number */
  698.     maxdig = '9';
  699.     } else if (operand[numstart] == '@') {
  700.     radix =    8;        /* Octal number    */
  701.     maxdig = '7';
  702.     } else if (operand[numstart] == '%') {
  703.     radix =    2;        /* Binary number */
  704.     maxdig = '1';
  705.     } else
  706.     radix =    0;        /* Not a number    */
  707.     if (local)
  708.     radix =    0;        /* Local variable - not    a number */
  709.  
  710.     if (radix != 0) {            /* Some    sort of    number */
  711.     result = 0;
  712.     if (radix != 10)
  713.         numstart++;            /* Allow for type character */
  714.     for (i = numstart; operand[i] != '\0'; i++) {
  715.         result *= radix;
  716.         if ((operand[i] >= '0') && (operand[i] <= maxdig))
  717.         result += (operand[i] -    '0');
  718.         else if (radix == 16)
  719.         if ((operand[i]    >= 'A') && (operand[i] <= 'F'))
  720.             result += (operand[i] - 'A' + 10);
  721.         else if    ((operand[i] >=    'a') && (operand[i] <= 'f'))
  722.             result += (operand[i] - 'a' + 10);
  723.         else
  724.             Error (loc + i, OperErr);
  725.         else
  726.         Error (loc + i,    OperErr);
  727.     }
  728.     } else if ((operand[0] == '\'') || (operand[0] == '"')) {
  729.     delim =    operand[0];        /* Character value delimiter */
  730.     result = 0;
  731.     i = 1;
  732.     while (1) {
  733.         if (operand[i] == '\0') {
  734.         Error (loc + i,    NoStrEnd);    /* End is missing */
  735.         break;
  736.         }
  737.         if (operand[i] == delim) {    /* End of string? */
  738.         if (operand[++i] != delim)    /* Check next character    */
  739.             break;        /* End of string */
  740.         }        /* Otherwise it's an apostrophe in the string */
  741.         result = (result <<    8) + operand[i++];
  742.     }
  743.     } else if ((operand[0] == '*') && (operand[1] == '\0')) {
  744.     result = AddrCnt;    /* Value of location counter */
  745.     Hunk2 =    CurrHunk;    /* Use current section's hunk number */
  746.     } else if (strcmp (operand,    "NARG") == 0) {
  747.     result = InF->NArg;        /* Number of arguments */
  748.     if (result == -1)
  749.         result = 0;            /* No arguments    outside    macros */
  750.     } else {
  751.     if (ReadSymTab (operand)) {    /* Look    up symbol */
  752.         AddRef (LineCount);        /* Found - add reference */
  753.         if (Sym->Flags & 0x60)
  754.         Error (loc, AddrErr);    /* Can't use a register equate */
  755.     } else
  756.         Error (loc,    Undef);        /* Undefined */
  757.     result = Value;
  758.     }
  759.     if (neg) {
  760.     result = -result;        /* Negative value */
  761.     if (Hunk2 != ABSHUNK)
  762.         Error (loc,    RelErr);    /* Must    be absolute */
  763.     }
  764.     return(result);
  765. }
  766.  
  767.  
  768.  
  769. AddSymTab (label, value, hunk, line, flags)
  770. char label[];
  771. long value, hunk;
  772. int line, flags;
  773. /* Inserts a new entry to the symbol table and updates NumSyms.
  774.    The insertion position is taken from    "Sym" - it must be
  775.     such that the table    will be    kept in    sequence by label.
  776.     "Sym" is set by "ReadSymTab".
  777.     If the label is a local label (i.e.    the first character is
  778.     a numeric digit or a backslash), the current contents of LabLine
  779.     will be converted to characters and    appended to the    label before
  780.     it is added.  If the first character of the    label is a backslash
  781.     (i.e. a named local    variable) a dollar sign    will be    appended
  782.     to the label ahead of the value of LabLine.            */
  783. {
  784. #ifdef USE_MOVMEM
  785.     register char *pj1,    *pj2;
  786.     register unsigned i;
  787. #else
  788.     register struct SymTab *pj1, *pj2;
  789. #endif
  790.     char wlab[MAXLINE],    wnum[6];
  791.  
  792.     strcpy (wlab, label);
  793.     if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
  794.     if (label[0] ==    '\\')
  795.         strcat (wlab, "$");
  796.     sprintf    (wnum, "%d", LabLine);  /* If it's a local label, */
  797.     strcat (wlab, wnum);        /*    append LabLine      */
  798.     }
  799.     HeapSpace (strlen(wlab)+1);    /* Make    sure we    have room */
  800. #ifdef USE_MOVMEM
  801.     pj2    = (char    *) SymStart;
  802.     SymStart--;
  803.     pj1    = (char    *) SymStart;
  804.     i =    (char *) Sym - pj2;
  805.     movmem (pj2, pj1, i);    /* Shift the table */
  806. #else
  807.     pj2    = SymStart;
  808.     SymStart--;
  809.     pj1    = SymStart;
  810.     while (pj2 < Sym) {        /* Shift the table */
  811.     pj1->Nam   = pj2->Nam;
  812.     pj1->Val   = pj2->Val;
  813.     pj1->Hunk  = pj2->Hunk;
  814.     pj1->Defn  = pj2->Defn;
  815.     pj1->Flags = pj2->Flags;
  816.     pj1->Ref1  = pj2->Ref1;
  817.     pj1++;
  818.     pj2++;
  819.     }
  820. #endif
  821.     Sect--;            /* Adjust section pointer */
  822.     Sym--;            /* Insert to left of search point */
  823.     Sym->Nam   = HeapLim;    /* Pointer to symbol */
  824.     Sym->Val   = value;        /* Value */
  825.     Sym->Hunk  = hunk;        /* Hunk    number */
  826.     Sym->Defn  = line;        /* Statement number */
  827.     Sym->Flags = flags;        /* Flags */
  828.     Sym->Ref1  = 0;        /* Reference pointer */
  829.     NumSyms++;            /* Count symbols */
  830.     strcpy (HeapLim, wlab);    /* Store the symbol */
  831.     HeapLim += strlen(wlab)+1;    /* Update heap limit */
  832. }
  833.  
  834.  
  835.  
  836. int ReadSymTab (label) char label[];
  837. /* Searches the    symbol table for the given label.
  838.    If not found, points    Sym to where the new entry should
  839.      be    inserted and returns FALSE.
  840.    If found, points Sym    to the proper table entry,
  841.      and sets up the following fields:
  842.     Value     - value of symbol
  843.     Hunk2     - hunk    number in which    symbol resides
  844.            ABSHUNK if value is absolute
  845.            ones    complement of symbol table index if external
  846.     DefLine2 - statement number in which symbol was    defined
  847.             (NODEF if undefined )
  848.     If the label is a local label (i.e.    the first character is
  849.     numeric), the current contents of LabLine will be converted
  850.     to characters and appended to the label before it is searched.
  851.     (This matches the way AddSymTab added the label to the table.)
  852.     If the first character of the label    is a backslash (i.e. a
  853.     named local    variable) a dollar sign    will be    appended to the
  854.     label ahead    of the value of    LabLine.            */
  855. {
  856.     register int lower,    upper, mid, search;
  857.     char wlab[MAXLINE],    wnum[6];
  858.  
  859.     strcpy (wlab, label);
  860.     if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
  861.     if (label[0] ==    '\\')
  862.         strcat (wlab, "$");
  863.     sprintf    (wnum, "%d", LabLine);  /* If it's a local label, */
  864.     strcat (wlab, wnum);        /*    append LabLine      */
  865.     }
  866.     for    (lower = 0, upper = NumSyms; lower < upper; ) {
  867.     mid = (lower + upper) /    2;
  868.     Sym = SymStart + mid;
  869.     search = strcmp    (wlab, Sym->Nam);
  870.     if (search < 0)
  871.         upper = mid;
  872.     else if    (search    > 0)
  873.         lower = mid    + 1;
  874.     else {
  875.         Value = Sym->Val;        /* Found it */
  876.         Hunk2 = Sym->Hunk &    0x0000FFFFL;
  877.         if (Hunk2 &    0x00008000L)
  878.         Hunk2 |= 0xFFFF0000L;    /* Extend sign */
  879.         DefLine2 = Sym->Defn;
  880.         return (TRUE);
  881.     }
  882.     }
  883.     Value = 0;            /* Didn't find it - */
  884.     Hunk2 = ABSHUNK;        /* set value to    absolute zero */
  885.     DefLine2 = NODEF;
  886.     Sym    = SymStart + lower;    /* Insert a new    entry here */
  887.     return (FALSE);
  888. }
  889.  
  890.  
  891.  
  892. AddRef (linenum) int linenum;
  893. /* Adds    "linenum" to the list of references
  894.     for    the symbol pointed to by Sym.        */
  895. {
  896.     register int i;
  897.     register struct Ref    *ref, *prevref;
  898.  
  899.     if (!Pass2)
  900.     return;            /* Pass    2 only!    */
  901.     if (!XrefList)
  902.     return;            /* No cross-reference */
  903.     prevref = 0;
  904.     ref    = Sym->Ref1;
  905.     while (ref)    {        /* Chase pointers */
  906.     for (i = 0; i <    MAXREF;    i++) {        /* Scan reference entry */
  907.         if (ref->RefNum[i] == 0) {        /*    for an empty slot   */
  908.         ref->RefNum[i] = linenum;   /* Insert new line number */
  909.         return;
  910.         }
  911.     }
  912.     prevref    = ref;            /* Remember where we were */
  913.     ref = ref->NextRef;        /* Link    to the next entry */
  914.     }
  915.     HeapSpace (sizeof (struct Ref));    /* Find    space for a new    entry */
  916.     RefStart--;
  917.     RefStart->NextRef =    0;        /* Pointer to next entry */
  918.     RefStart->RefNum[0]    = linenum;    /* First reference in new entry    */
  919.     for    (i = 1;    i < MAXREF; i++)
  920.     RefStart->RefNum[i] = 0;    /* Clear remaining slots */
  921.     if (prevref    == 0)
  922.     Sym->Ref1 = RefStart;        /* Link    to first entry */
  923.     else
  924.     prevref->NextRef = RefStart;    /* Link    to next    entry */
  925. }
  926.  
  927.  
  928.  
  929. int GetSize (symbol) char symbol[];
  930. /* Determines size of opcode/operand: Byte, Word, Long */
  931. {
  932.     register int  i;
  933.     register char c;
  934.  
  935.     i =    0;
  936.     while (1) {
  937.     c = symbol[i++];
  938.     if ((c == '\0') || (c == '.'))
  939.         break;
  940.     }
  941.     if (c == '\0')
  942.     return(Word);     /* Default to size Word = 16 bits */
  943.     else {
  944.     c = toupper (symbol[i]);    /* Record size extension */
  945.     symbol[i - 1] =    '\0';           /* Chop size extension off */
  946.     if ((c == 'B') || (c == 'S'))   /* Byte or Short Branch/Jump */
  947.         return(Byte);
  948.     else if    (c == 'L')              /* Long */
  949.         return(Long);
  950.     else
  951.         return(Word);        /* Default to Word */
  952.     }
  953. }
  954.  
  955.  
  956.  
  957. HeapSpace (n) int n;
  958. /* Die if we can't find "n" bytes of free space on the heap. */
  959. {
  960.     if ((HeapLim + n) >    (Pass2 ? (char *) RefStart : (char *) SymStart)) {
  961.     printf ("    \n%4d   %s\n", LineCount, Line);
  962.     printf ("Primary heap overflow - assembly terminated.\n");
  963.     free (Heap);
  964.     free (Heap2);
  965.     exit(20);
  966.     }
  967. }
  968.  
  969.  
  970.  
  971. Heap2Space (n) int n;
  972. /* Works like HeapSpace, but on    the secondary heap. */
  973. {
  974.     if ((NextFNS + n) >    (char *) InF) {
  975.     printf ("    \n%4d   %s\n", LineCount, Line);
  976.     printf ("Secondary heap overflow - assembly terminated.\n");
  977.     free (Heap);
  978.     free (Heap2);
  979.     exit(20);
  980.     }
  981. }
  982.  
  983.  
  984.  
  985. ParseSpace (n) int n;
  986. /* Special version of Heap2Space for the expression parser */
  987. {
  988.     if (((char *) Term + n) > (char *) Ops) {
  989.     printf ("    \n%4d   %s\n", LineCount, Line);
  990.     printf ("Secondary heap overflow - assembly terminated.\n");
  991.     free (Heap);
  992.     free (Heap2);
  993.     exit(20);
  994.     }
  995. }
  996.